package com.yuxinyang.memory.admin.common.utils;

import org.apache.tomcat.util.buf.HexUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 加密工具类
 *
 * @author 余秀良
 * @version 1.0
 * <p>date: 2019年09月04日  14:29 </p>
 * <p>address: 四川成都 </p>
 */
public class AesEncryptUtil {
    /**
     * 加密算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * 密钥
     */
    private static final String SEED = "7D2b&2bec28<4a98ae4/1d7ac0340849435c4@08926045!eb7Ff4a2f49d9dc03@2dfa2201#7e4f32a7$cea954d1e%012";
    /**
     * 偏移量
     */
    private static final int OFFSET = 16;
    /**
     * 算法名称/加密模式/填充方式
     * DES共有四种工作模式，ECB：电子密码本模式、CBC：加密分组链接模式、CFB：加密反馈模式、OFB：输出反馈模式
     */
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    /**
     * 密钥长度
     */
    private static final int KEY_SIZE = 256;

    /**
     * 加密
     *
     * @return 加密后的字符串
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 04  14:06    </p>
     * <p>  address: 四川成都  </p>
     */
    public static String encrypt(String value) {
        //执行操作
        byte[] result = encrypt(value.getBytes(StandardCharsets.UTF_8));
        return HexUtils.toHexString(result);
    }

    /**
     * 解密
     *
     * @return 解密后的字符串
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 04  14:06    </p>
     * <p>  address: 四川成都  </p>
     */
    public static String decrypt(String value) {
        byte[] bytes = HexUtils.fromHexString(value);
        byte[] decrypt = decrypt(bytes);
        assert decrypt != null;
        return new String(decrypt);
    }

    /**
     * 加密
     *
     * @param data 被加密的bytes
     * @return 加密后的bytes
     */
    private synchronized static byte[] encrypt(byte[] data) {
        try {
            Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
            byte[] bytes = cipher.doFinal(Base64.getEncoder().encode(data));
            return Base64.getEncoder().encode(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param bytes 待解密的数组
     * @return 解密后的数组
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 05  16:12    </p>
     * <p>  address: 四川成都  </p>
     */
    private synchronized static byte[] decrypt(byte[] bytes) {
        try {
            Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
            bytes = cipher.doFinal(Base64.getDecoder().decode(bytes));
            return Base64.getDecoder().decode(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获得加密或解密器
     *
     * @param mode 设置加密还是解密  解密：Cipher.DECRYPT_MODE  加密：Cipher.ENCRYPT_MODE
     * @return 加密或解密
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 05  16:07    </p>
     * <p>  address: 四川成都  </p>
     */
    private static Cipher getCipher(int mode) {
        Cipher cipher = null;
        try {
            byte[] encoded = getKeyGenerator().generateKey().getEncoded();
            SecretKeySpec secretKeySpec = new SecretKeySpec(encoded, ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(encoded, 0, OFFSET);
            cipher = Cipher.getInstance(TRANSFORMATION);
            // 初始化
            cipher.init(mode, secretKeySpec, iv);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return cipher;
    }

    /**
     * 获取密钥生成器
     *
     * @return {@link KeyGenerator}
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 06  09:04    </p>
     * <p>  address: 四川成都  </p>
     */
    private static KeyGenerator getKeyGenerator() {
        KeyGenerator generator = null;
        try {
            //构造密钥生成器，指定为AES算法
            generator = KeyGenerator.getInstance(ALGORITHM);
            MessageDigest digester = MessageDigest.getInstance("SHA-512");
            byte[] digest = digester.digest(SEED.getBytes(StandardCharsets.UTF_8));
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(digest);
            generator.init(KEY_SIZE, random);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return generator;
    }
}
